#ifndef FLOWGRAPHGENERATOR_H_
#define FLOWGRAPHGENERATOR_H_

#include "IGraphGenerator.h"

#include <boost/random.hpp>

#include "graph_support/attributes/FlowEdgeAttributes.h"
#include "graph_support/impls/vector/VectorGraph.h"
#include "graph_support/exceptions/GraphOperationException.h"


namespace native_orbitor
{

class FlowGraphGenerator : public IGraphGenerator
{
private:
	typedef GRAPH_SUPPORT_NS::impls::vector::VectorGraphTmpl<
			int,
			GRAPH_SUPPORT_NS::attributes::FlowEdgeAttributesTmpl< double >,
			stdext::hash< int >,
			stdext::equal_to< int >
			> Graph;
	typedef FlowGraphGenerator/*< Graph >*/ MyT;// TODO is not necessary for non-template
	typedef Graph::GrVertex GrVertex;

public:
	virtual std::auto_ptr< GraphPointerGuard > generateGraph(
			SettingsMap settingsMap )
	{
		// TODO: insert generation of different flow values
		// TODO: use easy graph generator !!! to reduce copy-paste !!!
		int verticesCount = getIntParam( settingsMap, "verticesCount" );
		int edgesCount = getIntParam( settingsMap, "edgesCount" );
		size_t randomSeed = getIntParam( settingsMap, "randomInt" );
		std::vector< GrVertex > vertices( verticesCount );
		for ( int i = 0; i < verticesCount; i++ )
		{
			vertices[i] = i;
		}

		boost::rand48 randomGenerator( randomSeed );

		std::auto_ptr< Graph > graphPtr( new Graph( vertices, true ) );
		Graph & graph = * graphPtr;
		for (int i = 0; i < edgesCount; i++) {
			size_t begVid = randomGenerator() % verticesCount;
			size_t endVid = randomGenerator() % verticesCount;
			// TODO: add edges was skipped
			graph.addEdge( graph.num2vert( begVid ), graph.num2vert( endVid ), 123 );
		}

		void ( * deleteGraphFunc ) ( GRAPH_SUPPORT_NS::Graph * ) = & MyT::deleteGraph;

		std::auto_ptr< GraphPointerGuard > result( new GraphPointerGuard( & graph, deleteGraphFunc ) );
		graphPtr.release();
		return result;
	}

// TODO remove this copy-paste from easy generator
private:
	static int getIntParam( const SettingsMap & settingsMap, const char * paramName )
	{
		SettingsMap::const_iterator found =
				settingsMap.find( paramName );
		if ( found == settingsMap.end() )
		{
			throw GRAPH_SUPPORT_NS::exceptions::GraphOperationException(
					std::string( "Parameter " ) + paramName + " wasn't found" );
		}
		return ( int ) found->second;
	}

	static void deleteGraph( GRAPH_SUPPORT_NS::Graph * abstractGraphPtr ) {
		Graph * graphPtr = dynamic_cast< Graph * >( abstractGraphPtr );
		assert( graphPtr );
		delete graphPtr;
	}
};

}

#endif /* FLOWGRAPHGENERATOR_H_ */
